<!DOCTYPE html>
<html lang="en">
<head>
		<title>SKiDL &mdash; Customized ERC!</title>
		<meta charset="utf-8" />
		<link rel="profile" href="http://gmpg.org/xfn/11" />
		<link rel="stylesheet" type="text/css" href="/skidl/theme/css/style.css" />
		<link rel='stylesheet' id='oswald-css'  href='http://fonts.googleapis.com/css?family=Oswald&#038;ver=3.3.2' type='text/css' media='all' />
		<link rel="preconnect" href="https://fonts.googleapis.com">
		<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
		<link href="https://fonts.googleapis.com/css2?family=Oswald&family=Roboto+Condensed&display=swap" rel="stylesheet">
		<!-- <style type="text/css">
			body.custom-background { background-color: #f5f5f5; }
		</style> -->
		<link rel="alternate" type="application/atom+xml"
			title="SKiDL — Flux Atom"
			href="/skidl/" />
		<!--[if lte IE 8]><script src="/skidl/theme/js/html5shiv.js"></script><![endif]-->
</head>

<body class="home blog custom-background " >
	<div id="container">
		<div id="header">
				<h1 id="site-title"><a href="/skidl"><img src="/skidl/images/banner.png" width="100%"></a></h1>
				<!-- <h1 id="site-title"><a href="/skidl">SKiDL</a></h1> -->
		</div><!-- /#banner -->

		<div id="menu">
			<div class="menu-navigation-container">
				<ul id="menu-navigation" class="menu">
						<li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="https://github.com/devbisme/skidl">Github</a></li>
						<li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="https://github.com/devbisme/skidl/discussions">Forum</a></li>
						<li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/skidl/category/posts.html">Blog</a></li>
						<li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/skidl/api/html/index.html">API</a></li>
						<li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/skidl/">Home</a></li>

				</ul>
			</div> <!--/#menu-navigation-container-->
		</div><!-- /#menu -->

		<div class="page-title">
		</div>

		<div id="contents">

<div class="post type-post status-publish format-standard hentry category-general" id="post">
	<div class="entry-meta">
		<span class="date"><a href="/skidl/customized-erc-2020-05-29.html">Fri 29 May 2020</a></span>
		/
		<span class="byline"><a href="/skidl/author/dave-vandenbout.html">Dave Vandenbout</a></span>
	</div> <!-- /#entry-meta -->
	<div class="main">
		<h2 class="entry-title">
			<a href="/skidl/customized-erc-2020-05-29.html" title="Permalink to Customized ERC!" rel="bookmark">Customized ERC!</a>
		</h2>
		<div class="entry-content">
			<p>Everybody wants ERC. Everybody hates ERC.</p>
<p>Electrical rules checking (ERC) looks for errors in how your circuit is constructed.
It's like running <a href="https://en.wikipedia.org/wiki/Lint_(software)"><code>lint</code></a>, but for hardware.
And as with <code>lint</code>, you get a whole bunch of warnings that don't matter but which
<em>obscure the ones that do</em>.</p>
<p>SKiDL tries to help by allowing you to
<a href="https://devbisme.github.io/skidl/docs/_site/index.html#selectively-supressing-erc-messages">selectively turn off ERC</a>
for nets, pins, and parts.
That fixes part of the problem.</p>
<p>The other part is the inflexibility of ERC: it has fixed rules for common errors
(like two outputs driving against each other), but adding rules for special cases
isn't easy.</p>
<p>The <code>erc_assert()</code> function was added to SKiDL to make customizing ERC easier.
With <code>erc_assert()</code>, you can add specialized rules that are checked only
in particular instances.
In the example below, <code>erc_assert()</code> is used to
flag nets that have too much fanout:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">skidl</span> <span class="kn">import</span> <span class="o">*</span>

<span class="c1"># Function to get the number of inputs on a net.</span>
<span class="k">def</span> <span class="nf">get_fanout</span><span class="p">(</span><span class="n">net</span><span class="p">):</span>
    <span class="n">fanout</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">get_pins</span><span class="p">():</span>
        <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">func</span> <span class="ow">in</span> <span class="p">(</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">BIDIR</span><span class="p">):</span>
            <span class="n">fanout</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">fanout</span>

<span class="n">net1</span><span class="p">,</span> <span class="n">net2</span> <span class="o">=</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN1&#39;</span><span class="p">),</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN2&#39;</span><span class="p">)</span>

<span class="c1"># Place some assertions on the fanout of each net.</span>
<span class="c1"># Note that the assertions are passed as strings.</span>
<span class="n">erc_assert</span><span class="p">(</span><span class="s1">&#39;get_fanout(net1) &lt; 5&#39;</span><span class="p">,</span> <span class="s1">&#39;failed on net1&#39;</span><span class="p">)</span>
<span class="n">erc_assert</span><span class="p">(</span><span class="s1">&#39;get_fanout(net2) &lt; 5&#39;</span><span class="p">,</span> <span class="s1">&#39;failed on net2&#39;</span><span class="p">)</span>

<span class="c1"># Attach some pins to the nets.</span>
<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span> <span class="o">*</span> <span class="mi">4</span>  <span class="c1"># This net passes the assertion.</span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span> <span class="o">*</span> <span class="mi">5</span>  <span class="c1"># This net fails because of too much fanout.</span>

<span class="c1"># When the ERC runs, it will also evaluate any erc_assert statements.</span>
<span class="n">ERC</span><span class="p">()</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code>ERC ERROR: get_fanout(net2) &lt; 5 failed on net2 in &lt;ipython-input-20-766848d35dca&gt;:16:&lt;module&gt;.

0 warnings found during ERC.
1 errors found during ERC.
</code></pre></div>

<p>You might ask: “Why not just use the standard Python <code>assert</code> statement?”
The reason is that a standard assertion is evaluated as soon as the <code>assert</code> statement
is encountered so the result might be incorrect if the nets
are not yet completely defined.
But the statement passed to the <code>erc_assert()</code> function is a <strong>string</strong> that
isn’t evaluated until all the circuitry has been connected and ERC() is called.
Note in the code above that when the <code>erc_assert()</code> function is called,
no pins are even attached to the <code>net1</code> or <code>net2</code> nets.
The <code>erc_assert()</code> function just places the statement to be checked into
a queue that gets evaluated when <code>ERC()</code> is run.
By then, the nets will have pins attached by then.</p>
<p>You can perform more complicated checks by creating a function and then placing a call
to it in the assertion string:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">skidl</span> <span class="kn">import</span> <span class="o">*</span>

<span class="k">def</span> <span class="nf">get_fanout</span><span class="p">(</span><span class="n">net</span><span class="p">):</span>
    <span class="n">fanout</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">get_pins</span><span class="p">():</span>
        <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">func</span> <span class="ow">in</span> <span class="p">(</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">BIDIR</span><span class="p">):</span>
            <span class="n">fanout</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">fanout</span>

<span class="c1"># Function to check a fanout constraint on a net and drop into</span>
<span class="c1"># the debugger if the constraint is violated.</span>
<span class="k">def</span> <span class="nf">check_fanout</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">threshold</span><span class="p">):</span>
    <span class="n">fanout</span> <span class="o">=</span> <span class="n">get_fanout</span><span class="p">(</span><span class="n">net</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">fanout</span> <span class="o">&gt;=</span> <span class="n">threshold</span><span class="p">:</span>
        <span class="c1"># Report the net which violated the constraint.&quot;</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">net</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s1"> fanout of </span><span class="si">{</span><span class="n">fanout</span><span class="si">}</span><span class="s1"> &gt;= </span><span class="si">{</span><span class="n">threshold</span><span class="si">}</span><span class="s1">.&#39;</span><span class="p">)</span>

        <span class="c1"># Drop into the debugger so you can query the circuit</span>
        <span class="c1"># and then continue.</span>
        <span class="nb">breakpoint</span><span class="p">()</span>

        <span class="k">return</span> <span class="kc">False</span>  <span class="c1"># Return False to trigger the erc_assert().</span>

    <span class="k">return</span> <span class="kc">True</span>  <span class="c1"># Return True if the constraint is not violated.</span>

<span class="n">net1</span><span class="p">,</span> <span class="n">net2</span> <span class="o">=</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN1&#39;</span><span class="p">),</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN2&#39;</span><span class="p">)</span>

<span class="c1"># Place calls to the check_fanout() function into the assertions.</span>
<span class="n">erc_assert</span><span class="p">(</span><span class="s1">&#39;check_fanout(net1, 5)&#39;</span><span class="p">)</span>
<span class="n">erc_assert</span><span class="p">(</span><span class="s1">&#39;check_fanout(net2, 5)&#39;</span><span class="p">)</span>

<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span> <span class="o">*</span> <span class="mi">4</span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span> <span class="o">*</span> <span class="mi">5</span>

<span class="n">ERC</span><span class="p">()</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code><span class="n">IN2</span><span class="w"> </span><span class="n">fanout</span><span class="w"> </span><span class="kr">of</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mf">5.</span>
<span class="o">&gt;</span><span class="w"> </span><span class="o">&lt;</span><span class="n">ipython</span><span class="o">-</span><span class="n">input</span><span class="o">-</span><span class="mi">18</span><span class="o">-</span><span class="mi">800</span><span class="n">a83e11624</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">22</span><span class="p">)</span><span class="n">check_fanout</span><span class="p">()</span>
<span class="o">-&gt;</span><span class="w"> </span><span class="kr">return</span><span class="w"> </span><span class="kr">False</span><span class="w">  </span><span class="err">#</span><span class="w"> </span><span class="kr">Return</span><span class="w"> </span><span class="kr">False</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">trigger</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">erc_assert</span><span class="p">().</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span><span class="w"> </span><span class="n">c</span>
<span class="n">ERC</span><span class="w"> </span><span class="nf">ERROR</span><span class="o">:</span><span class="w"> </span><span class="n">check_fanout</span><span class="p">(</span><span class="n">net2</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">)</span><span class="w"> </span><span class="n">FAILED</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="o">&lt;</span><span class="n">ipython</span><span class="o">-</span><span class="n">input</span><span class="o">-</span><span class="mi">18</span><span class="o">-</span><span class="mi">800</span><span class="n">a83e11624</span><span class="o">&gt;:</span><span class="mi">30</span><span class="o">:&lt;</span><span class="kr">module</span><span class="o">&gt;</span><span class="p">.</span>

<span class="mi">0</span><span class="w"> </span><span class="n">warnings</span><span class="w"> </span><span class="n">found</span><span class="w"> </span><span class="n">during</span><span class="w"> </span><span class="n">ERC</span><span class="p">.</span>
<span class="mi">1</span><span class="w"> </span><span class="n">errors</span><span class="w"> </span><span class="n">found</span><span class="w"> </span><span class="n">during</span><span class="w"> </span><span class="n">ERC</span><span class="p">.</span>
</code></pre></div>

<p>You can detect if a subcircuit is being used correctly by embedding calls to
<code>erc_assert()</code> to check inputs, outputs, and internal circuitry:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">skidl</span> <span class="kn">import</span> <span class="o">*</span>

<span class="c1"># Return True if the net has a pullup on it, False if not.</span>
<span class="k">def</span> <span class="nf">has_pullup</span><span class="p">(</span><span class="n">net</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">get_pins</span><span class="p">():</span>
        <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">func</span> <span class="o">==</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULLUP</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">True</span>

    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;No pullup on net </span><span class="si">{</span><span class="n">net</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span>
    <span class="k">return</span> <span class="kc">False</span>

<span class="nd">@subcircuit</span>
<span class="k">def</span> <span class="nf">some_circuit</span><span class="p">(</span><span class="n">in1</span><span class="p">,</span> <span class="n">in2</span><span class="p">):</span>
    <span class="c1"># Check the subcircuit inputs to see if they have pullups.</span>
    <span class="n">erc_assert</span><span class="p">(</span><span class="s1">&#39;has_pullup(in1)&#39;</span><span class="p">)</span>
    <span class="n">erc_assert</span><span class="p">(</span><span class="s1">&#39;has_pullup(in2)&#39;</span><span class="p">)</span>

    <span class="c1"># OK, this subcircuit doesn&#39;t really do anything, so you&#39;ll</span>
    <span class="c1"># just have to imagine that it did.</span>
    <span class="k">pass</span>

<span class="n">net1</span><span class="p">,</span> <span class="n">net2</span> <span class="o">=</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN1&#39;</span><span class="p">),</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN2&#39;</span><span class="p">)</span>

<span class="c1"># Instantiating the subcircuit automatically checks the input nets.</span>
<span class="n">some_circuit</span><span class="p">(</span><span class="n">net1</span><span class="p">,</span> <span class="n">net2</span><span class="p">)</span>

<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span>  <span class="c1"># No pullup -&gt; this net fails.</span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">PULLUP</span><span class="p">)</span>

<span class="n">ERC</span><span class="p">()</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code>No pullup on net IN1
ERC ERROR: has_pullup(in1) FAILED in &lt;ipython-input-16-6e72ef7d46c8&gt;:15:some_circuit.

0 warnings found during ERC.
1 errors found during ERC.
</code></pre></div>

<p>You can even use the <code>erc_assert()</code> function to add global checks
that scan the entire circuit for violations of custom rules:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">skidl</span> <span class="kn">import</span> <span class="o">*</span>

<span class="c1"># Global function that checks all the nets in the circuit and</span>
<span class="c1"># flags nets which have pullups when they shouldn&#39;t.</span>
<span class="k">def</span> <span class="nf">my_erc</span><span class="p">():</span>
    <span class="n">erc_result</span> <span class="o">=</span> <span class="kc">True</span>
    <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">default_circuit</span><span class="o">.</span><span class="n">get_nets</span><span class="p">():</span>
        <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="s1">&#39;disallow_pullups&#39;</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span> <span class="o">==</span> <span class="kc">True</span><span class="p">:</span>
            <span class="n">pin_types</span> <span class="o">=</span> <span class="p">[</span><span class="n">pin</span><span class="o">.</span><span class="n">func</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">get_pins</span><span class="p">()]</span>
            <span class="k">if</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULLUP</span> <span class="ow">in</span> <span class="n">pin_types</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Pull-up not allowed on </span><span class="si">{</span><span class="n">net</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s1">.&#39;</span><span class="p">)</span>
            <span class="n">erc_result</span> <span class="o">=</span> <span class="kc">False</span>
    <span class="k">return</span> <span class="n">erc_result</span>

<span class="n">net1</span><span class="p">,</span> <span class="n">net2</span> <span class="o">=</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN1&#39;</span><span class="p">),</span> <span class="n">Net</span><span class="p">(</span><span class="s1">&#39;IN2&#39;</span><span class="p">)</span>

<span class="n">net1</span><span class="o">.</span><span class="n">disallow_pullups</span> <span class="o">=</span> <span class="kc">True</span>  <span class="c1"># Don&#39;t allow pullups on this net.</span>
<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span>
<span class="n">net1</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">PULLUP</span><span class="p">)</span> <span class="c1"># This net will fail ERC. </span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span>
<span class="n">net2</span> <span class="o">+=</span> <span class="n">Pin</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">PULLUP</span><span class="p">)</span>

<span class="c1"># Call your own customized global ERC.</span>
<span class="n">erc_assert</span><span class="p">(</span><span class="s1">&#39;my_erc()&#39;</span><span class="p">)</span>

<span class="n">ERC</span><span class="p">()</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code>Pull-up not allowed on IN1.
ERC ERROR: my_erc() FAILED in &lt;ipython-input-12-888102e7799c&gt;:24:&lt;module&gt;.

0 warnings found during ERC.
1 errors found during ERC.
</code></pre></div>

<p>That's about it for the <code>erc_assert()</code> function.
Since it's new, it hasn't seen a lot of use so there could be
modifications that are needed to make it more useful.
If you have questions or problems, please ask on the
<a href="https://skidl.discourse.group/">SKiDL forum</a> or
raise an <a href="https://github.com/devbisme/skidl/issues">issue</a>. </p>
		</div> <!--/#entry-content-->
	</div> <!--/#main-->
</div>  <!--/#post-->

		</div>

		<div id="footer">
			<p> </p>
		</div><!-- /#footer -->
	</div><!-- /#container -->
	<div style="display:none"></div>
</body>
</html>